// 引入 Node.js 文件系统模块，用于读取目录/文件与写入 JSON
import fs from "node:fs";
// 引入 Node.js readline 模块，用于逐行读取文本内容
import readline from "readline";
// 引入 CryptoJS，用于生成稳定的内容 ID（MD5）
import CryptoJS from "crypto-js";

// Markdown 数据根目录（按语言分 en/zh）
const dataPath = 'pages/Doc';
// 存储数据路径
// 三方库数据输出JSON文件路径
const thirdPartyDataPath = "pages/Data/thirdParty.json";
// 活动数据输出 JSON 文件路径
const activityDataPath = "pages/Data/activity.json";
// 资讯数据输出 JSON 文件路径
const newsDataPath = "pages/Data/news.json";
// 课程数据输出 JSON 文件路径
const courseDataPath = "pages/Data/course.json";
// 电子书数据输出 JSON 文件路径
const ebookDataPath = "pages/Data/ebook.json";
// 社群矩阵数据输出 JSON 文件路径
const communityDataPath = "pages/Data/community.json";


// 处理数据：读取 Markdown 目录，按语言聚合生成三类 JSON
const getDataJson = async() => {
  // 读取语言目录列表（如 en、zh）
  const lanFiles = fs.readdirSync(dataPath);
  // 三方库聚合结果（按语言）
  let tpData = {};
  // 活动聚合结果（按语言）
  let aData = {};
  // 资讯聚合结果（按语言）
  let nData = {};
  // 课程聚合结果（按语言）
  let cData = {};
  // 电子书聚合结果（按语言）
  let eData = {};
  // 社群矩阵聚合结果（按语言）
  let cmData = {};
  // 遍历语言目录
  for await (const file of lanFiles) {
    try {
      // 读取该语言下的二级分类目录（activity/news/course）
      const files = fs.readdirSync(`${dataPath}/${file}`);
      // 遍历分类目录
      for await (const item of files) {
        // 处理活动分类
        if(item === 'activity') {
          // 聚合活动数据
          const activity = await getActivity(`${dataPath}/${file}/${item}`);
          // 有数据再写入对应语言键
          if(activity?.length) {
            aData[file] = activity;
          }
        // 处理资讯分类
        } else if(item === 'news') {
          // 聚合资讯数据（下钻子目录按子分类）
          const news = await getArticle(`${dataPath}/${file}/${item}`)
          nData[file] = news;
        // 处理课程分类
        } else if(item === 'course') {
          // 聚合课程数据
          const course = await getActivity(`${dataPath}/${file}/${item}`)
          cData[file] = course;
        // 处理电子书分类
        } else if (item === 'ebook') {
          // 聚合电子书数据
          const ebook = await getEbook(`${dataPath}/${file}/${item}`)
          if (ebook?.length) {
            eData[file] = ebook;
          }
        // 处理社群矩阵分类
        } else if (item === 'community') {
          const community = await getCommunity(`${dataPath}/${file}/${item}`)
          if (community?.length) {
            cmData[file] = community;
          }
		// 处理三方库分类
        } else if (item === "thirdParty") {
			// 聚合三方库数据
			const thirdParty = await getThirdParty(`${dataPath}/${file}/${item}`)
			tpData[file] = thirdParty;
		}
      }
    // 忽略单个语言目录处理中的异常（例如缺少某分类）
    } catch {}
  }
  // 将三方库聚合写入JSON文件
  fs.writeFileSync(thirdPartyDataPath, JSON.stringify(tpData));
  // 将活动聚合写入 JSON 文件
  fs.writeFileSync(activityDataPath, JSON.stringify(aData));
  // 将资讯聚合写入 JSON 文件
  fs.writeFileSync(newsDataPath, JSON.stringify(nData));
  // 将课程聚合写入 JSON 文件
  fs.writeFileSync(courseDataPath, JSON.stringify(cData));
  // 将电子书聚合写入 JSON 文件
  fs.writeFileSync(ebookDataPath, JSON.stringify(eData));
  // 将社群矩阵聚合写入 JSON 文件
  fs.writeFileSync(communityDataPath, JSON.stringify(cmData));
}
// 立即执行入口，生成三类 JSON 索引
getDataJson();

// 获取三方库数据：读取目录下所有Markdown并解析关键字段
const getThirdParty = async(path) => {
	// 获取三方库目录下的所有文件列表
	const thirdPartyFiles = fs.readdirSync(path);
	// 解析得到三方库数据数组
	const thirdPartyData = await getData(thirdPartyFiles, path);
	// 返回三方库数据集合
	return thirdPartyData;
}

// 获取电子书数据：读取目录下所有 Markdown 并解析关键字段
const getEbook = async(path) => {
  const ebookFiles = fs.readdirSync(path);
  const ebookData = await getData(ebookFiles, path);
  return ebookData;
}

// 获取社群矩阵数据
const getCommunity = async(path) => {
  // 读取社区矩阵目录下的所有文件列表
  const files = fs.readdirSync(path);
  // 解析得到社区矩阵数据数组
  const data = await getData(files, path);
  // 返回社区矩阵数据集合
  return data;
}

// 获取活动数据：读取目录下所有 Markdown 并解析关键字段
const getActivity = async(path) => {
  // 读取活动目录下的所有文件列表
  const activityFiles = fs.readdirSync(path);
  // 解析得到活动数据数组
  const activityData = await getData(activityFiles, path);
  // 返回活动数据集合
  return activityData;
}

// 获取文章数据（资讯）：按子目录（频道）聚合
const getArticle = async(path) => {
  // 读取资讯的一级子目录（如 资讯动态/运营月报 等）
  const files = fs.readdirSync(path);
  // 若存在子目录则继续处理
  if(files?.length) {
    // 以子目录名为键的对象，值为该目录下文章数组
    const newsData = {};
      // 遍历每个子目录
      for await (const file of files) {
        try {
          // 读取子目录下的 Markdown 文件列表
          const newsFiles = fs.readdirSync(`${path}/${file}`);
          // 解析成统一结构的数据数组
          newsData[file] = await getData(newsFiles, `${path}/${file}`);
        // 单个子目录异常忽略，不影响其他目录
        } catch {}
      }
    // 返回聚合后的对象
    return newsData
  }
}

// 获取某个目录下文件的数据：抽取 front-matter 关键字段并生成 id
const getData = async (files, path) => {
  // 最终数据数组
  const data = [];
  // 遍历文件名列表
  for await (const file of files) {
    try {
      // 读取单个文件的关键信息（front-matter）
      const key = await getKeyData(file, path);
      // 使用文件名生成稳定的 MD5 作为 id
      const id = CryptoJS.MD5(file).toString();
      // 汇总为统一结构
      data.push({
        id,
        path: `${path}/${file}`,
        ...key,
      });
    // 单个文件异常忽略，保证整体不中断
    } catch {}
  }
  // 返回该目录解析出的数据集合
  return data;
};

// 解析 md 文件头部的关键信息（简易 front-matter 解析）
const getKeyData = async (file, path) => {
  // 保存从 front-matter 抽取的键值
  const keyValue = {};
  // 创建可读流逐行读取 Markdown 文件
  const readStream = fs.createReadStream(`${path}/${file}`);
  // 创建 readline 接口，按行处理
  const rl = readline.createInterface({
    input: readStream,
    crlfDelay: Infinity,
  });
  // 是否处于 front-matter 块（--- 与 --- 之间）
  let isStart = false;
  // 逐行读取
  for await (const line of rl) {
    // 命中分隔线，切换 front-matter 解析状态
    if (line === "---") {
      if (isStart) {
        // 结束 front-matter 解析
        isStart = false;
        rl.close();
      } else {
        // 开始 front-matter 解析
        isStart = true;
      }
    // 处于 front-matter 且当前行为非空时尝试解析键值
    } else if (isStart && line) {
      try {
        // 以 key: value 或 key：value 匹配，提取键值
        const [content, key, value] = line.match(/^(\w+)[:：](.*)$/);
        // 去掉值两端空白并写入结果
        keyValue[key] = value.trim();
      // 单行不符合匹配规则时忽略
      } catch {}
    }
  }
  // 返回解析到的前置信息
  return keyValue;
};
